package cis.view;

import cis.model.State;

import java.awt.Color;
import java.awt.Graphics;

import java.awt.event.ActionEvent;
import java.util.Iterator;

/**
 * StateIncomeView.java
 * 
 * CS2334 010 Programming Structures and Abstractions
 * Project #5
 * April 4, 2010
 * 
 * <p>
 * This class is responsible for make the data that is contained within a Place 
 * class visible to the user.  This data is salary demographics of a certain 
 * county/metro area/ etc.
 * </p>
 *
 * @version 1.0
 * 
 */
public class StateIncomeView extends AbstractPieChart {
	/** Eclipse generated serial version id. */
	private static final long serialVersionUID = -3813987372362753735L;
	/** This Place that holds the data that will be registered with this 
	    view component. */
	private State state;
	
	///////////////////////
	// Constructors      //
	////////////////////////////////////////////////////////////////////////////	
	/**
	 * <p>
	 * Argumented constructor that will create a Pie Chart and display the GUI 
	 * with the data stored in the Place that is passed.
	 * </p>
	 * 
	 * @param place The Place that contains the data that key will be graphed.
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  All GUI elements need to be initialized.</dd>
	 * <dd>POST: All GUI elements are assigned values and <code>place</code> is 
	 *           assigned the value passed.  <code>place</code> is then graphed 
	 *           by the view and the data is made visible to the requester.</dd>
	 * </dt>
	 */
	public StateIncomeView(State state) {
		this.state = state;
		this.getFrame().setVisible(true);
	}	// end constructor
	
	///////////////////////////////////
	// Mutators                      //
	////////////////////////////////////////////////////////////////////////////
	/**
	 * <p>
	 * The action that will be performed when this action listener is trigger by 
	 * a change in the data model.
	 * </p>
	 * 
	 * @param e The event that triggered this action listener.
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  This class must be assign as an action listener to the data 
	 *           model.</dd>
	 * <dd>POST: This class will perform a repaint of the panel upon data 
	 *           change.</dd>
	 * </dt>
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		repaint();
	}	// end method
	
	/**
	 * <p>
	 * This method will paint this view with custom elements of the key, title 
	 * and the actual pie chart that shows the data.
	 * </p>
	 * 
	 * @param g The graphics class that will hold all the functions for painting 
	 *          this panel with custom elements.
	 *          
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  There must be a <code>place</code> assigned to this class.</dd>
	 * <dd>POST: The data that is contained within <code>place</code> is drawn 
	 *           to the panel.</dd>
	 * </dt>
	 */
	@Override
	public void paintComponent(Graphics g) {
		g.clearRect(0, 0, 1000, 600);
		this.drawTitle(g);
		this.drawChart(g);
	}	// end method
		
	/**
	 * <p>
	 * Paints the title to the panel.
	 * </p>
	 * 
	 * @param g The Graphics class that contains the functions to paint to this 
	 *          panel.
	 *          
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  <code>place</code> must be assigned a value.</dd>
	 * <dd>POST: The title is constructed from data contained within 
	 *           <code>place</code>.</dd>
	 * </dt>
	 */
	public void drawTitle(Graphics g) {
		g.setColor(Color.BLACK);
		g.drawString(state.getName() + " Income Distribution", 10, 20);
	}	// end method
	
	///////////////////////////////////
	// Accessors                     //
	////////////////////////////////////////////////////////////////////////////
	/**
	 * <p>
	 * Acquires the place that is being drawn to this panel.
	 * </p>
	 * 
	 * @return The value stored by <code>place</code>.
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  <code>place</code> must be assigned a value.</dd>
	 * <dd>POST: The value stored by <code>place</code> is returned to the 
	 *           requester.</dd>
	 * </dt>
	 */
	public State getState() {
		return this.state;
	}	// end method
	
	/**
	 * <p>
	 * Sets the place that will be graphed to the panel.
	 * </p>
	 * 
	 * @param place The place that contains the data to be graphed.
	 * @param stateName The name of the state to be graphed.
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  The value passed must contain data to be graphed.</dd>
	 * <dd>POST: The data is pie charted.</dd>
	 * </dt>
	 */
	public void setState(State state) {
		this.state = state;
		repaint();
	}	// end method

	/**
	 * <p>
	 * Acquires all the slices for the renderable data that is present in the 
	 * place class passed.
	 * </p>
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  <code>place</code> must contain a value.  This is why there is 
	 *           only one constructor for this class.</dd>
	 * <dd>POST: The data that is contained within <code>place</code> is 
	 *           compiled into a slice list.</dd>
	 * </dt>
	 */
	@Override
	public void getSlices() {
		// Make sure we start with a clear slice list.
		this.slices.clear();
		// All possibilities for slices
		Iterator<Integer> values = state
		                           .getIncomeDemographics().values().iterator();
		Iterator<String>  keys  = state
		                           .getIncomeDemographics().keySet().iterator();
		// The slice dividing factor
		int totalHouseholds = state.getHouseholdCount();
		
		// The offset angle for each slice
		int totalAngle      = 0;
		
		// Calculate all values for all slices
		while(values.hasNext() && keys.hasNext()) {
			Integer households = values.next();
			String  key        = keys.next();
			
			// No need to waste the space for a slice if it does not need render
			if(households.intValue() == 0) {
				// Do not draw this entry
			} else {
				// Calculate the angle of this slice
				float angle = ((float)households.intValue() / 
						(float)totalHouseholds) * 360f;
				// Tall that against the total angular measure
				totalAngle += (int)Math.round(angle);
				
				// Add the slice to the slice list for render
				this.slices.add(new Slice(totalAngle, Math.round(angle), 
						generateColor(), key));
			}	// end if
		}	// end while
	}	// end method
}	// end class
